;; =============
;; EXERCISE 2.06
;; =============

;; In case representing pairs as procedures wasn’t mind-boggling
;; enough, consider that, in a language that can manipulate
;; procedures, we can get by without numbers (at least insofar as
;; nonnegative integers are concerned) by implementing 0 and the
;; operation of adding 1 as

(define zero
  (lambda (f) (lambda (x) x)))

(define (add-1 church-numeral)
  (λ (func)
    (λ (x)
      ;; Add one more application therefore increasing the
      ;; church-numeral by one. A church-numeral applied to a function
      ;; will return a function, which is applied to a given input the
      ;; amount of times, which was represented by the church-numeral.
      (func ((church-numeral func) x)))))

;; This representation is known as Church numerals, after its
;; inventor, Alonzo Church, the logician who invented the λ- calculus.

;; Define one and two directly (not in terms of zero and add-
;; 1). (Hint: Use substitution to evaluate (add-1 zero)).

;; Give a direct definition of the addition procedure + (not in terms
;; of repeated application of add-1).

;; =============
;; SOLUTION 2.06
;; =============

;; A

;; Define one and two directly (not in terms of zero and add-
;; 1). (Hint: Use substitution to evaluate (add-1 zero)).

(define one
  (λ (func)
    (λ (something)
      ;; Apply func once.
      (func something))))

(define two
  (λ (func)
    (λ (something)
      ;; Apply func twice.
      (func (func something)))))

;; B

;; Give a direct definition of the addition procedure + (not in terms
;; of repeated application of add-1).

(define add
  ;; Take two church-numerals as input.
  (λ (church-numeral-1 church-numeral-2)
    ;; Return a church-numeral, which expects a function as input.
    (λ (func)
      ;; The function will be applied to something as many times as
      ;; the church-numeral represents.
      (λ (something)
        ;; First apply func church-numeral-1 times on the input.
        ;; Then apply func additinally church-numeral-2 times on the input.
        ((church-numeral-2 func) ((church-numeral-1 func) something))))))

;; =====
;; TESTS
;; =====

(use-modules (srfi srfi-64))

(test-begin "test-cons-car-cdr")
(test-group
 "test-cons-car-cdr"
 (test-equal
     2 ((one (lambda (sth) (+ 1 sth))) 1))
 (test-equal
     3 ((two (lambda (sth) (+ 1 sth))) 1))
 (test-equal
     4 (((add two one) (lambda (sth) (+ 1 sth))) 1))
 (test-equal
     5 (((add (add-1 two) one) (lambda (sth) (+ 1 sth))) 1))
 (test-equal
     6 (((add (add-1 (add-1 two)) one) (lambda (sth) (+ 1 sth))) 1)))
(test-end "test-cons-car-cdr")
